#pragma once

#include <common/common_utils.hpp>
#include <common/generic_model.hpp>
#include <common/global_id_cache.hpp>
#include <common/uni_define.h>

// third_party
#include <nlohmann/json.hpp>

// table
#include <model/db/goods/inventory.h>

// DTO for inventory table
struct InventoryDTO {
  inline static const std::vector<std::string> required_fields = {
    "goods_id", "warehouse_id", "quantity", "min_threshold", "max_threshold"};


  in_id_type id = 0;
  in_id_type goods_rk_id = 0;
  in_id_type warehouse_rk_id = 0;
  quantity_type quantity = 0.0;
  quantity_type min_threshold = 0.0;
  quantity_type max_threshold = 0.0;
  datetime_type last_updated = {};

  static InventoryDTO from_json(const nlohmann::json& j)
  {
    auto& cache = GlobalIdCache::getInstance();
    return InventoryDTO{
      .goods_rk_id =
        cache.getInternalId("goods", j.at("goods_id").get<std::string>()),
      .warehouse_rk_id = cache.getInternalId(
        "warehouse", j.at("warehouse_id").get<std::string>()),
      .quantity = j.at("quantity").get<quantity_type>(),
      .min_threshold = j.at("min_threshold").get<quantity_type>(),
      .max_threshold = j.at("max_threshold").get<quantity_type>()};
  }
};

inline void to_json(nlohmann::json& j, const InventoryDTO& inventory_dto)
{
  auto& cache = GlobalIdCache::getInstance();
  j = nlohmann::json{
    {"goods_id", cache.getExternalId("goods", inventory_dto.goods_rk_id)},
    {"warehouse_id",
     cache.getExternalId("warehouse", inventory_dto.warehouse_rk_id)},
    {"quantity", inventory_dto.quantity},
    {"min_threshold", inventory_dto.min_threshold},
    {"max_threshold", inventory_dto.max_threshold},
    {"last_updated", utils::datetime_to_string(inventory_dto.last_updated)}};
}

// ORM mapping
namespace model {
template <> struct ReflectTable<InventoryDTO, db::inventory> {
  static constexpr auto map_members = std::make_tuple(
    std::make_pair(&InventoryDTO::id, &db::inventory::id),
    std::make_pair(&InventoryDTO::goods_rk_id, &db::inventory::goods_rk_id),
    std::make_pair(&InventoryDTO::warehouse_rk_id,
                   &db::inventory::warehouse_rk_id),
    std::make_pair(&InventoryDTO::quantity, &db::inventory::quantity),
    std::make_pair(&InventoryDTO::min_threshold, &db::inventory::min_threshold),
    std::make_pair(&InventoryDTO::max_threshold, &db::inventory::max_threshold),
    std::make_pair(&InventoryDTO::last_updated, &db::inventory::last_updated));
};

// mapping
template <typename InventoryRow>
struct ReflectTableRow<InventoryDTO, InventoryRow> {
  static InventoryDTO assign_model(InventoryRow&& row)
  {
    return InventoryDTO{.id = row.id,
                        .goods_rk_id = row.goods_rk_id,
                        .warehouse_rk_id = row.warehouse_rk_id,
                        .quantity = row.quantity,
                        .min_threshold = row.min_threshold,
                        .max_threshold = row.max_threshold,
                        .last_updated = row.last_updated};
  }
};

}  // namespace model
